// 对象劫持的方法
(function () {
    return
    let data = {
        key: 11
    };
    Object.defineProperty(data, 'key', {
        enumerable: true,
        configurable: true,
        get: function () {
            console.log('我是get')
            return this._key
        },
        set: function (newVal) {
            if (this._key == newVal) {
                return
            }
            console.log('我是set')
            this._key = newVal
        }
    })
    let a = data.key
    data.key = 56
    // data.key = 11
    // console.log(data.key)

})();

// getter中收集依赖，在setter中触发依赖
(function () {

    return
    let obj = {}
    let target = function (n, o) {
        console.log("this==>是我", n, o)
    }
    let defineReactive = function (data, key, val) {
        // 这里面的val其实是个变量, 参数的val相当于是第一次赋值
        let dep = [] // 新增
        Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            get: function () {
                dep.push(target) // 新增
                console.log('woshi get')
                return val
            },
            set: function (newVal) {
                if (val === newVal) {
                    console.log(val)
                    return
                }
                // 新增
                for (let i = 0; i < dep.length; i++) {
                    dep[i](newVal, val)
                }
                val = newVal
            }
        })

    }
    defineReactive(obj, "aa", 77)
    // let a = obj.aa
    // obj.aa = 89
    // obj.aa = 77
    console.log(obj.aa)// 这就相当于赋值了
})();

//解析简单路径函数
; (function () {
    return
    const bailRE = /[^\w.$]/
    let parsePath = function (path) {
        if (bailRE.test(path)) {
            return
        }
        const segments = path.split('.')
        return function (obj) {
            for (let i = 0; i < segments.length; i++) {
                if (!obj) return
                console.log(segments[i]);
                obj = obj[segments[i]]
                console.log(obj);
            }
            console.log("我是obj==>", segments)
            return obj
        }
    };
    let obj = {
        obj1: {
            a: 1
        }
    }
    console.log(parsePath('obj1.a')(obj))
})();

// 简单测试Watcher添加到对象值得dep中
; (function () {
    return
    /**
     * 解析简单路径
     */
    const bailRE = /[^\w.$]/
    let parsePath = function (path) {
        if (bailRE.test(path)) {
            return
        }
        const segments = path.split('.')
        return function (obj) {
            for (let i = 0; i < segments.length; i++) {
                if (!obj) return
                obj = obj[segments[i]]
            }
            return obj
        }
    };
    let remove = function (arr, item) {
        if (arr.length) {
            const index = arr.indexOf(item)
            if (index > -1) {
                return arr.splice(index, 1)
            }
        }
    };
    // 这个是一个实例类 
    let windowTarget = {};

    class Dep {
        constructor() {
            this.subs = []
        }

        addSub(sub) {
            this.subs.push(sub)
        }

        removeSub(sub) {
            remove(this.subs, sub)
        }

        depend() {
            if (windowTarget) {
                this.addSub(windowTarget)
            }
        }

        notify() {
            const subs = this.subs.slice()
            for (let i = 0, l = subs.length; i < l; i++) {
                subs[i].update()
            }
        }
    }

    let defineReactive = function (data, key, val) {
        let dep = new Dep()
        observeSub = dep // 修改
        Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            get: function () {
                dep.depend() // 修改
                return val
            },
            set: function (newVal) {
                if (val === newVal) {
                    return
                }
                val = newVal
                dep.notify() // 新增
            }
        })
    };

    class Watcher {
        constructor(vm, expOrFn, cb) {
            this.vm = vm
            // 执行this.getter()，就可以读取data.a.b.c的内容
            this.getter = parsePath(expOrFn)
            this.cb = cb
            this.value = this.get()
        }

        get() {
            windowTarget = this
            let value = this.getter.call(this.vm, this.vm)
            windowTarget = undefined
            return value
        }

        update() {
            const oldValue = this.value
            this.value = this.getter.call(this.vm, this.vm)
            this.cb.call(this.vm, this.value, oldValue)
        }
    }
    let observeSub = []
    let obj = {
        a: 1
    }

    defineReactive(obj, "a", 1)
    let watcher = new Watcher(obj, 'a', function (val, old) {
        console.log('这个是val==>', val);
        console.log('这个是old==>', old);
    })
    console.log(observeSub)
    obj.a = 2

    obj.a = 5
    console.log(observeSub)

})();

// 增加递归测试Watcher添加到对象值得dep中
; (function () {
    // return
    /**
     * 解析简单路径
     */
    const bailRE = /[^\w.$]/
    let parsePath = function (path) {
        if (bailRE.test(path)) {
            return
        }
        const segments = path.split('.')
        return function (obj) {
            for (let i = 0; i < segments.length; i++) {
                if (!obj) return
                obj = obj[segments[i]]
            }
            return obj
        }
    };
    let remove = function (arr, item) {
        if (arr.length) {
            const index = arr.indexOf(item)
            if (index > -1) {
                return arr.splice(index, 1)
            }
        }
    };
    // 这个是一个实例类 
    let windowTarget = {};

    class Dep {
        constructor() {
            this.subs = []
        }

        addSub(sub) {
            this.subs.push(sub)
        }

        removeSub(sub) {
            remove(this.subs, sub)
        }

        depend() {
            if (windowTarget) {
                this.addSub(windowTarget)
            }
        }

        notify() {
            const subs = this.subs.slice()
            for (let i = 0, l = subs.length; i < l; i++) {
                subs[i].update()
            }
        }
    }


    class Watcher {
        constructor(vm, expOrFn, cb) {
            this.vm = vm
            // 执行this.getter()，就可以读取data.a.b.c的内容
            this.getter = parsePath(expOrFn)
            this.cb = cb
            this.value = this.get()
        }

        get() {
            windowTarget = this
            let value = this.getter.call(this.vm, this.vm)
            windowTarget = undefined
            return value
        }

        update() {
            const oldValue = this.value
            this.value = this.getter.call(this.vm, this.vm)
            this.cb.call(this.vm, this.value, oldValue)
        }
    }
   
  
    /**
  * Observer类会附加到每一个被侦测的object上。
  * 一旦被附加上，Observer会将object的所有属性转换为getter/setter的形式
  * 来收集属性的依赖，并且当属性发生变化时会通知这些依赖
  */
    class Observer {
        constructor(value) {
            this.value = value

            if (!Array.isArray(value)) {
                this.walk(value)
            }
        }

        /**
         * walk会将每一个属性都转换成getter/setter的形式来侦测变化
         * 这个方法只有在数据类型为Object时被调用
         */
        walk(obj) {
            const keys = Object.keys(obj)
            for (let i = 0; i < keys.length; i++) {
                // console.log(JSON.stringify(obj), keys[i],JSON.stringify(obj[keys[i]]))
                defineReactive(obj, keys[i], obj[keys[i]])
            }
        }
    }

    function defineReactive(data, key, val) {
        // 新增，递归子属性
        if (typeof val === 'object') {
            new Observer(val)
        }
        let dep = new Dep()
        // 这里可以看到所有的属性都递归劫持了
        // console.log(JSON.stringify(val));
        // 1
        // "b"
        // {}
        // {"a":1,"b":"b","c":{}}
        // ======
        // 这里可以看到每次data是那个对象了
        // console.log(JSON.stringify(data));
        // {"a":1,"b":"b","c":{}}
        // {"a":1,"b":"b","c":{}}
        // {"a":1,"b":"b","c":{}}
        // {"data":{"a":1,"b":"b","c":{}}}
        Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            get: function () {
                dep.depend()
                console.log("get中val",val)
                return val
            },
            set: function (newVal) {
                if (val === newVal) {
                    return
                }
                
                val = newVal
                console.log("set中newVal",val)
                dep.notify()
            }
        })

        new Watcher(data, key, function (val, old) {
            console.log('Watcher是val==>', val);
            console.log('Watcher是old==>', old);
        })
    }

   

    let observeSub = []
    let obj = {
        data: {
            a:1,
            b:"b",
            c:{}
        }
    }

    defineReactive(obj, "data", obj.data)
    let a = obj.data.a
    // 这个是obj.data  先是获取了data
    // ==>get中val { a: [Getter/Setter], b: [Getter/Setter], c: [Getter/Setter] }
    // 这个是obj.data.a
    // get中val 1



    // obj.data.a = 5

    // 这个是obj.data  先是获取了data
    // ==> get中val { a: [Getter/Setter], b: [Getter/Setter], c: [Getter/Setter] }
    
    // obj.data.a中的set函数检测到了变化
    // ==> set中newVal 5

    // wacth中先获取val值出发了一次get
    // ==>get中val 5

    // wacth的回调函数
    // ==>Watcher是val==> 5
    // ==>Watcher是old==> 1

    

})();

